package com.quyeying.interceptor;

import com.quyeying.annotation.CacheLock;
import com.quyeying.service.redis.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * redisson 方案
 * @author shenkaixin
 */
@Slf4j
@Aspect
@Configuration
public class LockMethodInterceptor {

    @Autowired
    public LockMethodInterceptor(RedisService redisService) {
        this.redisService = redisService;
    }

    private final RedisService redisService;

    @Autowired
    RedissonClient redissonClient;

    @Around("execution(public * *(..)) && @annotation(com.quyeying.annotation.CacheLock)")
    public Object interceptor(ProceedingJoinPoint pjp) {
        Object object = null;
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        CacheLock cacheLock = method.getAnnotation(CacheLock.class);
        if (StringUtils.isEmpty(cacheLock.prefix())) {
            throw new RuntimeException("key前缀不能为空...");
        }
        final String lockKey = redisService.getLockKey(pjp);
        //定义锁
        RLock lock = redissonClient.getLock(lockKey);
        try {
            //尝试加锁
            if (lock.tryLock(0, cacheLock.expire(), TimeUnit.SECONDS)) {
                log.info("加锁成功，key：{}", lockKey);
                object = pjp.proceed();
            }else {
                throw new RuntimeException("请勿重复请求");
            }
        } catch (InterruptedException e) {
            log.info("系统错误");
            e.printStackTrace();
        } catch (Throwable e) {
            e.printStackTrace();
        } finally {
            //自动释放锁
        }
        return object;
    }
}

